//
//  Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//

import Foundation

@objc
public extension TSThread {

    var isGroupThread: Bool {
        return (self as? TSGroupThread) != nil
    }

    var isGroupV1Thread: Bool {
        guard let groupThread = self as? TSGroupThread else {
            return false
        }
        return groupThread.groupModel.groupsVersion == .V1
    }

    var isGroupV2Thread: Bool {
        guard let groupThread = self as? TSGroupThread else {
            return false
        }
        return groupThread.groupModel.groupsVersion == .V2
    }

    var groupModelIfGroupThread: TSGroupModel? {
        guard let groupThread = self as? TSGroupThread else {
            return nil
        }
        return groupThread.groupModel
    }

    var isBlockedByMigration: Bool {
        isGroupV1Thread && GroupManager.areMigrationsBlocking
    }

    var canSendToThread: Bool {
        !isBlockedByMigration
    }
}

// MARK: -

public extension TSThread {

    struct LastVisibleInteraction: Codable, Equatable {
        public let sortId: UInt64
        public let onScreenPercentage: CGFloat

        public init(sortId: UInt64, onScreenPercentage: CGFloat) {
            self.sortId = sortId
            self.onScreenPercentage = onScreenPercentage
        }
    }

    private static let lastVisibleInteractionStore = SDSKeyValueStore(collection: "lastVisibleInteractionStore")

    @objc
    func hasLastVisibleInteraction(transaction: SDSAnyReadTransaction) -> Bool {
        nil != Self.lastVisibleInteraction(forThread: self, transaction: transaction)
    }

    @objc
    func lastVisibleSortId(transaction: SDSAnyReadTransaction) -> NSNumber? {
        guard let lastVisibleInteraction = lastVisibleInteraction(transaction: transaction) else {
            return nil
        }
        return NSNumber(value: lastVisibleInteraction.sortId)
    }

    func lastVisibleInteraction(transaction: SDSAnyReadTransaction) -> LastVisibleInteraction? {
        Self.lastVisibleInteraction(forThread: self, transaction: transaction)
    }

    static func lastVisibleInteraction(forThread thread: TSThread,
                                       transaction: SDSAnyReadTransaction) -> LastVisibleInteraction? {
        guard let data = lastVisibleInteractionStore.getData(thread.uniqueId, transaction: transaction) else {
            return nil
        }
        do {
            return try JSONDecoder().decode(LastVisibleInteraction.self, from: data)
        } catch {
            owsFailDebug("Error: \(error)")
            return nil
        }
    }

    @objc
    func clearLastVisibleInteraction(transaction: SDSAnyWriteTransaction) {
        Self.setLastVisibleInteraction(nil, forThread: self, transaction: transaction)
    }

    @objc
    func setLastVisibleInteraction(sortId: UInt64,
                                   onScreenPercentage: CGFloat,
                                   transaction: SDSAnyWriteTransaction) {
        let lastVisibleInteraction = LastVisibleInteraction(sortId: sortId, onScreenPercentage: onScreenPercentage)
        Self.setLastVisibleInteraction(lastVisibleInteraction, forThread: self, transaction: transaction)
    }

    func setLastVisibleInteraction(_ lastVisibleInteraction: LastVisibleInteraction?,
                                   transaction: SDSAnyWriteTransaction) {
        Self.setLastVisibleInteraction(lastVisibleInteraction, forThread: self, transaction: transaction)
    }

    static func setLastVisibleInteraction(_ lastVisibleInteraction: LastVisibleInteraction?,
                                          forThread thread: TSThread,
                                          transaction: SDSAnyWriteTransaction) {
        guard let lastVisibleInteraction = lastVisibleInteraction else {
            lastVisibleInteractionStore.removeValue(forKey: thread.uniqueId, transaction: transaction)
            return
        }
        let data: Data
        do {
            data = try JSONEncoder().encode(lastVisibleInteraction)
        } catch {
            owsFailDebug("Error: \(error)")
            lastVisibleInteractionStore.removeValue(forKey: thread.uniqueId, transaction: transaction)
            return
        }
        lastVisibleInteractionStore.setData(data, key: thread.uniqueId, transaction: transaction)
    }
}
